<template>
	<view class="container">
		<!-- 地图容器 -->
    <view class="map-container" :class="{ 'fullscreen': isMapFullscreen }">
			<view class="map-header">
				<text class="map-title">监测点分布</text>
				<view class="header-right">
					<button class="location-btn" @click="toggleMapFullscreen">
						<uni-icons type="arrowup" size="18"></uni-icons>
						<text class="location-text">{{ isMapFullscreen ? '还原' : '放大' }}</text>
					</button>
					<text class="device-count">设备总数: {{ deviceList?.length || 0 }}</text>
					<button class="location-btn" @click="requestLocation">
						<text class="location-icon">📍</text>
						<text class="location-text">定位</text>
					</button>
			</view>
				</view>
			<!-- 用户位置信息 -->
			<view class="user-location" v-if="userLocation?.address">
				<text class="location-text">📍 {{ userLocation.address }}</text>
			</view>
			
			<!-- 日期标签选择器 -->
			<view class="date-selector" v-if="threeDayPrediction.length > 0">
				<view class="selector-header">
					<text class="selector-title">选择预测日期：</text>
					<button class="clear-all-btn" @click="clearAllPredictionData">
						<uni-icons type="trash" size="14" color="#fff"></uni-icons>
						<text>清除所有</text>
					</button>
				</view>
				<view class="date-tags">
					<view 
						class="date-tag" 
						:class="{ 'active': selectedDateIndex === index, 'polluted': day.isPolluted }"
						v-for="(day, index) in threeDayPrediction" 
						:key="index"
						@click="selectDate(index)"
					>
						<text class="date-text">{{ day.date }}</text>
						<text class="status-text" :class="day.status">{{ day.statusText }}</text>
					</view>
				</view>
			</view>
			<!-- 腾讯地图组件：H5 使用 JS API 容器，小程序使用原生 map 组件 -->
			<!-- #ifdef H5 -->
			<view id="tencentMap" class="map-component"></view>
			<!-- #endif -->

			<!-- #ifdef MP-WEIXIN -->
			<map
				id="tencentMap"
				class="map-component"
				:longitude="mapConfig?.center?.[0] || 115.489120"
				:latitude="mapConfig?.center?.[1] || 38.814788"
				:scale="mapConfig?.zoom || 10"
				:markers="markers"
				:show-location="true"
				:enable-3D="false"
				:enable-overlooking="false"
				:enable-zoom="true"
				:enable-scroll="true"
				:enable-rotate="false"
				:enable-satellite="false"
				:enable-poi="true"
				:show-compass="false"
				:show-scale="true"
				:min-scale="3"
				:max-scale="20"
				:key="mapConfig?.key"
				@markertap="onMarkerTap"
				@regionchange="onRegionChange"
				@updated="onMapUpdated"
				@tap="onMapTap"
			>
				<cover-view class="map-legend">
					<cover-view class="legend-item">
						<cover-view class="legend-color online"></cover-view>
						<cover-text class="legend-text">在线</cover-text>
					</cover-view>
					<cover-view class="legend-item">
						<cover-view class="legend-color offline"></cover-view>
						<cover-text class="legend-text">离线</cover-text>
					</cover-view>
					<cover-view class="legend-item">
						<cover-view class="legend-color fault"></cover-view>
						<cover-text class="legend-text">故障</cover-text>
					</cover-view>
				</cover-view>
			</map>
			<!-- #endif -->
		</view>
		
		<!-- 地图控制面板 -->
		<view class="control-panel">
			<view class="panel-header">
				<text class="panel-title">监测点分布</text>
				<view class="legend">
					<view class="legend-item">
						<view class="legend-dot online"></view>
						<text class="legend-text">在线</text>
					</view>
					<view class="legend-item">
						<view class="legend-dot offline"></view>
						<text class="legend-text">离线</text>
					</view>
					<view class="legend-item">
						<view class="legend-dot fault"></view>
						<text class="legend-text">故障</text>
					</view>
				</view>
			</view>
			<view class="update-hint">数据每分钟自动更新 · 最近：{{ lastUpdated || '—' }}</view>
			
			<!-- 设备列表 -->
			<scroll-view scroll-y class="device-list">
				<view class="device-item" :class="{ 'fault-device': device.status === 'fault' }" v-for="device in deviceList" :key="device.id" @click="selectDevice(device)">
					<view class="device-info">
						<view class="device-header">
							<text class="device-name" :class="{ 'fault-name': device.status === 'fault' }">{{ device.name }}</text>
						<text class="status-text" :class="{ 'fault-status': device.status === 'fault' }">{{ getStatusText(device.status) }}</text>
							<view class="device-status" :class="device.status"></view>
						</view>
						<text class="device-location" :class="{ 'fault-location': device.status === 'fault' }">{{ device.location }}</text>
						<view class="device-data">
							<text class="data-item" :class="{ 'fault-data-item': isPhFault(device.ph) }">pH: {{ device.ph }}</text>
							<text class="data-item" :class="{ 'fault-data-item': isTempFault(device.temp) }">温度: {{ device.temp }}°C</text>
							<text class="data-item" :class="{ 'fault-data-item': isNtuFault(device.ntu) }">浊度: {{ device.ntu }} NTU</text>
						</view>
						<!-- 污染预测按钮 -->
						<view class="device-actions">
							<button class="predict-btn" @click.stop="startPollutionPrediction(device)" :disabled="isPredicting">
								<text v-if="isPredicting && selectedDevice?.id === device.id">预测中...</text>
								<text v-else>污染预测</text>
							</button>
						</view>
					</view>
					<uni-icons type="right" size="16" :color="device.status === 'fault' ? '#ff4444' : '#ccc'"></uni-icons>
				</view>
			</scroll-view>
		</view>
		
		<!-- 底部统计 -->
		<view class="bottom-stats">
			<view class="stat-item">
				<text class="stat-number">{{ stats?.total || 0 }}</text>
				<text class="stat-label">总设备</text>
			</view>
			<view class="stat-item">
				<text class="stat-number online">{{ stats?.online || 0 }}</text>
				<text class="stat-label">在线</text>
			</view>
			<view class="stat-item">
				<text class="stat-number offline">{{ stats?.offline || 0 }}</text>
				<text class="stat-label">离线</text>
			</view>
			<view class="stat-item">
				<text class="stat-number fault">{{ stats?.fault || 0 }}</text>
				<text class="stat-label">故障</text>
			</view>
		</view>
	</view>
	
	<!-- 设备信息弹窗 -->
	<DeviceInfoModal
		:visible="showDeviceModal"
		:device="selectedDevice"
		@close="closeDeviceModal"
	/>

	<!-- 污染预测结果弹窗 -->
	<view class="prediction-modal" v-if="showPredictionModal" @click="closePredictionModal">
		<view class="modal-content" @click.stop>
			<view class="modal-header">
				<text class="modal-title">污染预测分析结果</text>
				<text class="close-btn" @click="closePredictionModal">×</text>
			</view>

			<view class="modal-body">
				<!-- 设备信息 -->
				<view class="device-info-section" v-if="selectedDevice">
					<text class="section-title">监测设备信息</text>
					<view class="info-item">
						<text class="info-label">设备名称：</text>
						<text class="info-value">{{ selectedDevice.name }}</text>
					</view>
					<view class="info-item">
						<text class="info-label">位置：</text>
						<text class="info-value">{{ selectedDevice.location }}</text>
					</view>
					<view class="info-item">
						<text class="info-label">坐标：</text>
						<text class="info-value">{{ selectedDevice.latitude }}, {{ selectedDevice.longitude }}</text>
					</view>
				</view>

				<!-- 污染状态 -->
				<view class="pollution-status-section" v-if="predictionResult?.isPolluted !== undefined">
					<text class="section-title">污染检测状态</text>
					<view class="pollution-status" :class="{ 'polluted': predictionResult.isPolluted, 'normal': !predictionResult.isPolluted }">
						<uni-icons :type="predictionResult.isPolluted ? 'fire' : 'checkmarkempty'" size="20" :color="predictionResult.isPolluted ? '#ff4444' : '#4cd964'"></uni-icons>
						<text>{{ predictionResult.isPolluted ? '检测到污染' : '水质正常' }}</text>
					</view>
				</view>

				<!-- 附近化工厂分析 -->
				<view class="factory-analysis-section" v-if="predictionResult?.nearbyFactories">
					<text class="section-title">附近化工厂分析</text>
					<view class="factory-list">
						<view class="factory-item" v-for="factory in predictionResult.nearbyFactories" :key="factory.id">
							<view class="factory-header">
								<text class="factory-name">{{ factory.name }}</text>
								<text class="factory-distance">{{ factory.distance }}km</text>
							</view>
							<view class="factory-details">
								<text class="factory-industry">行业：{{ factory.industry }}</text>
								<text class="factory-pollutants">主要污染物：{{ factory.mainPollutants }}</text>
								<text class="factory-risk" :class="factory.riskLevel">风险等级：{{ factory.riskLevel }}</text>
							</view>
						</view>
					</view>
				</view>

				<!-- 污染预测结果 -->
				<view class="prediction-result-section" v-if="predictionResult?.prediction">
					<text class="section-title">污染预测结果</text>
					<view class="prediction-content">
						<text class="prediction-text">{{ predictionResult.prediction }}</text>
					</view>
				</view>

				<!-- 建议措施 -->
				<view class="recommendations-section" v-if="predictionResult?.recommendations">
					<text class="section-title">建议措施</text>
					<view class="recommendations-list">
						<text class="recommendation-item" v-for="(rec, index) in predictionResult.recommendations" :key="index">
							{{ index + 1 }}. {{ rec }}
						</text>
					</view>
				</view>

				<!-- 污染区域控制 -->
				<view class="pollution-area-control-section" v-if="showPollutionAreas && predictionResult?.isPolluted">
					<text class="section-title">污染区域控制</text>
					<view class="control-buttons">
						<button class="control-btn clear-btn" @click="clearPollutionAreas">
							<uni-icons type="trash" size="16" color="#fff"></uni-icons>
							<text>清除污染区域</text>
						</button>
						<button class="control-btn info-btn" @click="showPollutionAreaInfo">
							<uni-icons type="info" size="16" color="#fff"></uni-icons>
							<text>区域信息</text>
						</button>
					</view>
				</view>

				<!-- 模拟污染控制 -->
				<view class="simulate-pollution-section">
					<text class="section-title">模拟污染演示</text>
					<view class="simulate-buttons">
						<button class="simulate-btn light-pollution-btn" @click="simulateLightPollution" :disabled="isSimulating">
							<uni-icons type="warning" size="16" color="#fff"></uni-icons>
							<text>{{ isSimulating ? '模拟中...' : '轻度污染' }}</text>
						</button>
						<button class="simulate-btn simulate-pollution-btn" @click="simulatePollution" :disabled="isSimulating">
							<uni-icons type="fire" size="16" color="#fff"></uni-icons>
							<text>{{ isSimulating ? '模拟中...' : '严重污染' }}</text>
						</button>
						<button class="simulate-btn reset-btn" @click="resetPollutionSimulation">
							<uni-icons type="refresh" size="16" color="#fff"></uni-icons>
							<text>重置状态</text>
						</button>
					</view>
				</view>
			</view>
		</view>
	</view>
</template>

<script setup>
// 放大/还原地图容器
const isMapFullscreen = ref(false)
const toggleMapFullscreen = () => {
	isMapFullscreen.value = !isMapFullscreen.value
	// H5下切换尺寸后，触发一次重绘和中心复位
	// #ifdef H5
	setTimeout(() => {
		if (window.h5MapInstance && window.qq?.maps) {
			const center = new window.qq.maps.LatLng(
				mapConfig.value.center[1],
				mapConfig.value.center[0]
			)
			window.qq.maps.event.trigger(window.h5MapInstance, 'resize')
			window.h5MapInstance.setCenter(center)
		}
	}, 300)
	// #endif
}
import { ref, onMounted, onUnmounted, computed, watch } from 'vue'
import { onShow, onHide } from '@dcloudio/uni-app'
import { useDeviceStore } from '@/stores/device.js'
import { getLatestRedisData } from '@/api/waterQuality.js'
import { getMapDeviceList, getDeviceLatestData } from '@/api/device.js'
import { pollutionApi } from '@/api/pollution.js'
import { TENCENT_MAP_CONFIG } from '@/config/tencent-map.js'
// 引入 uni-icons 组件
import uniIcons from '@dcloudio/uni-ui/lib/uni-icons/uni-icons.vue'

// 引入自定义弹窗组件
import DeviceInfoModal from '@/components/DeviceInfoModal.vue'

const deviceStore = useDeviceStore()

// 地图配置
const mapConfig = ref(TENCENT_MAP_CONFIG)

// 腾讯地图 SDK 实例
const qqmapsdk = ref({})

// 用户位置信息
const userLocation = ref({
	latitude: 38.814788,
	longitude: 115.489120,
	address: ''
})

// 监测指标正常范围
const NORMAL_RANGE = {
	ph: { min: 6.5, max: 8.5 },
	temp: { min: 20, max: 30 },
	ntu: { min: 0, max: 3000 } // 浊度 < 3000 视为正常
}

// 真实数据监测点ID（仅此一个从后端取值，其余为模拟）
const REAL_DEVICE_ID = "ESP8266_001"

// 监测点001的真实数据对象
const realDeviceData = ref({
	id: "ESP8266_001",
	name: "监测点001",
	location: "河北省保定市莲池区博学路",
	latitude: 38.814788,
	longitude: 115.489120,
	ph: 7.12,
	temp: 28,
	ntu: 0,
	status: "online"
})

// 响应式数据 - 只保留监测点001，其他数据从后端API获取
const deviceList = ref([
	// 监测点001使用真实数据对象
	realDeviceData.value
])

const stats = ref({
	total: 0,
	online: 0,
	offline: 0,
	fault: 0
})

// 最近一次模拟更新时间
const lastUpdated = ref('')

// 弹窗相关
const showDeviceModal = ref(false)
const selectedDevice = ref(null)

// 污染预测相关状态
const isAnalyzing = ref(false)
const isPredicting = ref(false)
const showPredictionModal = ref(false)
const predictionResult = ref(null)

// 污染区域相关状态
const pollutionAreas = ref([]) // 存储污染区域数据
const showPollutionAreas = ref(false) // 是否显示污染区域

// 模拟污染相关状态
const isSimulating = ref(false)
const isSimulatedPollution = ref(false)
const simulatedPollutionData = ref(null)

// 三天预测数据和日期选择
const threeDayPrediction = ref([])
const selectedDateIndex = ref(0)

// 逆地理编码防抖
const reverseGeocodeCache = new Map()
const reverseGeocodeTimers = new Map()

// 地图标记点
const markers = computed(() => {
	return deviceList.value.map((device, index) => ({
		id: device.id,
		latitude: device.latitude,
		longitude: device.longitude,
		title: device.name,
		width: 20,
		height: 20,
		// 直接在这里设置图标路径，利用 computed 自动更新
		iconPath: getMarkerIcon(device.id),
		callout: {
            content: `${device.name}\n${device.location}\n状态: ${getStatusText(device.status)}\n pH: ${device.ph}  温度: ${device.temp}°C  浊度: ${device.ntu}NTU`,
			color: '#333',
			fontSize: 12,
			borderRadius: 4,
			bgColor: '#fff',
			padding: 8,
			display: 'BYCLICK'
		}
	}))
})


onMounted(() => {
	console.log('地图页面加载完成')
	
	// 1. 校验地图Key
	if (!mapConfig.value || !mapConfig.value.key) {
		console.error('错误：腾讯地图Key未配置，请检查 @/config/tencent-map.js')
		uni.showModal({
			title: '配置错误',
			content: '腾讯地图Key未配置，地图功能无法使用',
			showCancel: false
		})
		return
	}
	
	// 2. 校验Key格式（腾讯地图Key支持两种格式：32位字符串或35位带连字符）
	const keyLength = mapConfig.value.key.length
	const isValidFormat = keyLength === 32 || (keyLength === 35 && mapConfig.value.key.includes('-'))
	if (!isValidFormat) {
		console.error('错误：腾讯地图Key格式无效（应为32位字符串或35位带连字符格式）')
		uni.showModal({
			title: 'Key无效',
			content: '当前腾讯地图Key格式错误，请检查配置',
			showCancel: false
		})
		return
	}
	
	// 3. 后续初始化逻辑
	console.log('设备列表:', deviceList.value)
	console.log('统计数据:', stats.value)
	console.log('地图配置:', mapConfig.value)
	console.log('当前使用的 Key:', mapConfig.value.key)
	initTencentMap()
	loadDeviceData()

	// 注意：定时器现在在onShow中启动，避免重复启动
})

onUnmounted(() => {
	stopSimulateTimer()
	stopRealDataTimer()
	clearPollutionAreas()
})

// 页面显示时立即获取数据并启动定时器
onShow(() => {
	console.log('地图页面显示，立即获取数据并启动定时器')
	// 立即获取一次真实数据
	fetchRealDeviceLatest()
	// 启动定时器
	startSimulateTimer()
	startRealDataTimer()
})

// 页面隐藏时停止定时器并清理污染区域
onHide(() => {
	console.log('地图页面隐藏，停止定时器')
	stopSimulateTimer()
	stopRealDataTimer()
	clearPollutionAreas()
})

// ---------------- 模拟数据与状态判定 ----------------
let simulateTimer = null

const clamp = (val, min, max) => Math.max(min, Math.min(max, val))

const randomDrift = (base, step, min, max) => {
	// 在 [-step, +step] 内微调，避免跳变过大
	const delta = (Math.random() * 2 - 1) * step
	return clamp(base + delta, min, max)
}

const computeStatusFromMetrics = (ph, temp, ntu) => {
	const phOk = ph >= NORMAL_RANGE.ph.min && ph <= NORMAL_RANGE.ph.max
	const tempOk = temp >= NORMAL_RANGE.temp.min && temp <= NORMAL_RANGE.temp.max
	const ntuOk = ntu >= NORMAL_RANGE.ntu.min && ntu <= NORMAL_RANGE.ntu.max
	return phOk && tempOk && ntuOk ? 'online' : 'fault'
}

// 判断单个数据项是否异常
const isPhFault = (ph) => {
	return ph < NORMAL_RANGE.ph.min || ph > NORMAL_RANGE.ph.max
}

const isTempFault = (temp) => {
	return temp < NORMAL_RANGE.temp.min || temp > NORMAL_RANGE.temp.max
}

const isNtuFault = (ntu) => {
	return ntu < NORMAL_RANGE.ntu.min || ntu > NORMAL_RANGE.ntu.max
}

const updateStats = () => {
	const total = deviceList.value.length
	let online = 0, fault = 0, offline = 0
	deviceList.value.forEach(d => {
		if (d.status === 'online') online++
		else if (d.status === 'fault') fault++
		else offline++
	})
	stats.value = { total, online, offline, fault }
}

const simulateOnce = () => {
	deviceList.value = deviceList.value.map(d => {
		// 只对监测点001进行模拟数据更新，其他设备保持从数据库获取的真实数据
		if (d.id === REAL_DEVICE_ID) {
			// 真实点位保持不动（或在其他逻辑中更新）
			return d
		}
		
		// 对于从数据库获取的设备，不进行模拟数据更新
		// 它们的数据应该通过API实时获取
		return d
	})
	updateStats()
    // 更新时间戳
    const pad = (n) => (n < 10 ? '0' + n : '' + n)
    const now = new Date()
    lastUpdated.value = `${pad(now.getHours())}:${pad(now.getMinutes())}:${pad(now.getSeconds())}`
}

function startSimulateTimer() {
	if (simulateTimer) return
	// 立即执行一次
	simulateOnce()
	// 每30秒执行一次，让数据变化更频繁
	simulateTimer = setInterval(simulateOnce, 30 * 1000)
}

function stopSimulateTimer() {
	if (simulateTimer) {
		clearInterval(simulateTimer)
		simulateTimer = null
	}
}

// 初始化腾讯地图（使用函数声明，避免初始化前访问问题）
function initTencentMap() {
	// 1. 小程序环境（优先修复，因为 H5 需额外配置）
	// #ifdef MP-WEIXIN
	try {
		// 正确引入 SDK（路径需和你的项目实际路径一致，避免文件找不到）
		const QQMapWX = require('../../common/lib/qqmap-wx-jssdk.min.js')
		// 使用配置文件的 Key，而非硬编码
		const mapKey = mapConfig.value.key
		if (!mapKey) {
			console.error('腾讯地图 Key 未配置，请检查 @/config/tencent-map.js')
			uni.showToast({ title: '地图Key未配置', icon: 'none' })
			return
		}
		// 初始化 SDK 实例（全局唯一）
		qqmapsdk.value = new QQMapWX({ key: mapKey })
		console.log('小程序 - 腾讯地图 SDK 初始化成功')
		
		// 初始化地图组件（关键：让地图实例绑定到页面的 map 组件）
		initMap()
		// 获取用户位置，更新地图中心点
		getUserLocation()
	} catch (error) {
		console.error('小程序 - 地图 SDK 加载失败:', error)
		uni.showToast({ title: '地图加载失败', icon: 'none' })
	}
	// #endif

	// 2. H5 环境（需额外引入 SDK 脚本，因为 H5 不支持 require 本地 SDK）
	// #ifdef H5
	console.log('H5 环境 - 加载腾讯地图 SDK 脚本')
	
	// 1. 先清除已有脚本和全局回调，避免重复定义
	const oldScript = document.querySelector('script[src*="map.qq.com/api/js"]')
	if (oldScript) oldScript.remove()
	if (window.initTencentMapH5) delete window.initTencentMapH5

	// 2. 动态插入新脚本
	const script = document.createElement('script')
	script.src = `https://map.qq.com/api/js?v=2.exp&key=${mapConfig.value.key}&callback=initTencentMapH5&libraries=geometry`
	script.onerror = () => {
		console.error('H5 - 地图 SDK 加载失败')
		uni.showToast({ title: 'H5地图加载失败', icon: 'none' })
	}
	
	// 3. 定义全局回调（添加防重复执行逻辑）
	window.initTencentMapH5 = () => {
		if (window.h5MapInstance) { // 若地图已初始化，直接更新定位
			console.log('H5 - 地图已初始化，跳过重复创建')
			getUserLocation()
			return
		}
		console.log('H5 - 腾讯地图 SDK 加载成功')
		initMapForH5()
		getUserLocation()
	}
	
	document.body.appendChild(script)
	// #endif
}

// 添加辅助函数：使用默认位置
const showLocationFallback = () => {
	console.log('H5环境：使用默认位置')
	const defaultLat = 38.814788
	const defaultLng = 115.489120
	
	userLocation.value = {
		latitude: defaultLat,
		longitude: defaultLng,
		address: '使用默认位置（北京）'
	}
	
	// 更新地图中心到默认位置
	updateMapCenter(defaultLng, defaultLat)
	
	uni.showToast({
		title: '使用默认位置',
		icon: 'none',
		duration: 2000
	})
}


// 添加辅助函数：更新地图中心
const updateMapCenter = (longitude, latitude) => {
	// #ifdef H5
	if (window.qq && window.qq.maps && window.h5MapInstance) {
		try {
			// 确保坐标是有效的数字
			const lat = parseFloat(latitude)
			const lng = parseFloat(longitude)
			
			// 验证坐标范围
			if (isNaN(lat) || isNaN(lng)) {
				console.error('H5 - 无效的坐标值:', { latitude, longitude })
				return
			}
			
			if (lat < -90 || lat > 90 || lng < -180 || lng > 180) {
				console.error('H5 - 坐标超出有效范围:', { lat, lng })
				return
			}
			
			console.log('H5 - 准备更新地图中心:', { lat, lng })
			
			// 创建LatLng对象
			const newCenter = new window.qq.maps.LatLng(lat, lng)
			console.log('H5 - LatLng对象创建成功:', newCenter)
			
			// 更新地图中心
			window.h5MapInstance.setCenter(newCenter)
			console.log('H5 - 地图中心点已更新到用户位置')
			
		} catch (error) {
			console.error('H5 - 更新地图中心失败:', error)
			console.error('H5 - 错误详情:', {
				latitude,
				longitude,
				lat: parseFloat(latitude),
				lng: parseFloat(longitude),
				qqMaps: !!window.qq?.maps,
				h5MapInstance: !!window.h5MapInstance
			})
		}
	} else {
		console.error('H5 - 地图实例未初始化或腾讯地图SDK未加载')
	}
	// #endif
	
	// #ifdef MP-WEIXIN
	// 小程序环境：更新地图中心
	console.log('小程序 - 准备更新地图中心:', { longitude, latitude })
	
	// 确保坐标是有效的数字
	const lat = parseFloat(latitude)
	const lng = parseFloat(longitude)
	
	// 验证坐标范围
	if (isNaN(lat) || isNaN(lng)) {
		console.error('小程序 - 无效的坐标值:', { latitude, longitude })
		return
	}
	
	if (lat < -90 || lat > 90 || lng < -180 || lng > 180) {
		console.error('小程序 - 坐标超出有效范围:', { lat, lng })
		return
	}
	
	// 更新地图配置中的中心点
	mapConfig.value.center = [lng, lat]
	console.log('小程序 - 地图中心点已更新:', mapConfig.value.center)
	// #endif
}

// 添加辅助函数：逆地址解析（获取地址文本）
const getAddressFromLocation = (latitude, longitude) => {
	// #ifdef H5
	if (!window.qq || !window.qq.maps) return
	
	try {
		const geocoder = new window.qq.maps.Geocoder({
			complete: (result) => {
				console.log('H5环境：逆地址解析成功', result)
				if (result && result.detail && result.detail.address) {
					userLocation.value.address = result.detail.address
					console.log('H5环境：地址解析结果', result.detail.address)
				} else if (result && result.detail && result.detail.formatted_address) {
					userLocation.value.address = result.detail.formatted_address
					console.log('H5环境：地址解析结果（备用）', result.detail.formatted_address)
				} else {
					console.warn('H5环境：逆地址解析结果格式异常', result)
					userLocation.value.address = '地址解析中...'
				}
			},
			error: (error) => {
				console.error('H5环境：逆地址解析失败', error)
				userLocation.value.address = '无法获取详细地址'
			}
		})
		
		geocoder.getAddress(new window.qq.maps.LatLng(latitude, longitude))
		} catch (error) {
			console.error('H5环境：逆地址解析异常', error)
			userLocation.value.address = '无法获取详细地址'
		}
	// #endif
}


// 定位到固定坐标
function getUserLocation(options = {}) {
	console.log('定位到固定坐标')
	
	// 显示定位成功提示
	uni.showToast({
		title: '定位成功',
		icon: 'success',
		duration: 2000
	})
	
	// 更新用户位置为固定坐标
	userLocation.value = {
		latitude: 38.814788,
		longitude: 115.489120,
		address: '固定位置 (115.489120, 38.814788)'
	}
	
	// 更新地图中心
	updateMapCenter(
		userLocation.value.longitude,
		userLocation.value.latitude
	)
	
	console.log('定位到固定坐标完成:', userLocation.value)
	
	// 触发定位完成回调，关闭加载提示
	options.onComplete?.()
}

// 新增 H5 地图初始化方法（H5 不支持 uni 的 map 组件，需用官方 JS API）
function initMapForH5() {
	// 1. 检查 SDK 是否加载
	if (!window.qq || !window.qq.maps) {
		console.error('H5 - 地图 SDK 未加载完成')
		return
	}

	// 2. 重试获取地图容器（最多重试3次，间隔500ms）
	let retryCount = 0
	const getMapContainer = () => {
		const mapContainer = document.getElementById('tencentMap')
		if (mapContainer) {
			initMapInstance(mapContainer) // 初始化地图实例
		} else if (retryCount < 3) {
			retryCount++
			setTimeout(getMapContainer, 500)
			console.log(`H5 - 重试获取地图容器（${retryCount}/3）`)
		} else {
			console.error('H5 - 多次重试仍未找到地图容器')
			// 显示错误占位符
			const containerParent = document.querySelector('.map-container')
			if (containerParent) {
				containerParent.innerHTML += `
					<div style="height:500rpx;display:flex;align-items:center;justify-content:center;color:#f44336;">
						地图容器加载失败，请刷新页面重试
					</div>
				`
			}
		}
	}

	// 3. 初始化地图实例（拆分逻辑，提高可读性）
	const initMapInstance = (mapContainer) => {
		try {
			const center = new window.qq.maps.LatLng(
				mapConfig.value.center[1],
				mapConfig.value.center[0]
			)
			window.h5MapInstance = new window.qq.maps.Map(mapContainer, {
				center: center,
				zoom: mapConfig.value.zoom || 10,
				disableDefaultUI: false,
				// 启用缩放控制
				zoomControl: true,
				scrollwheel: true, // 启用鼠标滚轮缩放
				disableDoubleClickZoom: false, // 启用双击缩放
				gestureHandling: 'auto' // 自动处理手势
			})
			console.log('H5 - 地图初始化成功')
			
			// 添加鼠标滚轮事件监听
			mapContainer.addEventListener('wheel', (e) => {
				e.preventDefault()
				console.log('H5 - 鼠标滚轮事件:', e.deltaY)
				
				// 根据滚轮方向调整缩放
				const currentZoom = window.h5MapInstance.getZoom()
				const newZoom = e.deltaY < 0 ? currentZoom + 1 : currentZoom - 1
				
				// 限制缩放范围
				const clampedZoom = Math.max(3, Math.min(20, newZoom))
				
				window.h5MapInstance.setZoom(clampedZoom)
				mapConfig.value.zoom = clampedZoom
				
				console.log('H5 - 缩放级别更新为:', clampedZoom)
			}, { passive: false })
            // 初始化信息窗
            if (!window.h5InfoWindow) {
                window.h5InfoWindow = new window.qq.maps.InfoWindow({ map: window.h5MapInstance })
            }

            // 初始化标记点容器
            if (!window.h5MarkersById) window.h5MarkersById = {}
            // 初始化圆形围栏容器
            if (!window.h5CirclesById) window.h5CirclesById = {}

            // 添加标记点和圆形围栏（H5）
            deviceList.value.forEach(device => {
                const position = new window.qq.maps.LatLng(device.latitude, device.longitude)
                
                // 添加标记点
                const marker = new window.qq.maps.Marker({
                    position,
                    map: window.h5MapInstance,
                    title: device.name
                })

                // 设置状态颜色图标
                const color = getStatusColor(device.status)
                const iconUrl = buildStatusSvgDataUrl(color, device.status)
                const size = new window.qq.maps.Size(24, 24)
                const markerImage = new window.qq.maps.MarkerImage(iconUrl, null, null, null, size)
                marker.setIcon(markerImage)

                // 添加圆形围栏
                const fillColor = new window.qq.maps.Color(33, 150, 243, 0.3) // 蓝色，30%透明度
                const strokeColor = new window.qq.maps.Color(33, 150, 243, 0.8) // 蓝色边框，80%透明度
                
                const circle = new window.qq.maps.Circle({
                    center: position,
                    radius: 2000, // 2公里半径，单位：米
                    map: window.h5MapInstance,
                    fillColor: fillColor,
                    strokeColor: strokeColor,
                    strokeWeight: 3
                })

                // 绑定点击展示信息窗
                window.qq.maps.event.addListener(marker, 'click', () => {
                    const isFault = device.status === 'fault'
                    const faultStyle = isFault ? 'color: #ff4444; font-weight: bold;' : ''
                    const faultBgStyle = isFault ? 'background-color: #fff5f5; border: 2px solid #ff4444; border-radius: 8px; padding: 8px;' : ''
                    
                    // 判断每个数据项是否异常
                    const phFault = isPhFault(device.ph)
                    const tempFault = isTempFault(device.temp)
                    const ntuFault = isNtuFault(device.ntu)
                    
                    const phStyle = phFault ? 'color: #ff4444; font-weight: bold; background-color: #fff0f0; padding: 2px 4px; border-radius: 4px;' : ''
                    const tempStyle = tempFault ? 'color: #ff4444; font-weight: bold; background-color: #fff0f0; padding: 2px 4px; border-radius: 4px;' : ''
                    const ntuStyle = ntuFault ? 'color: #ff4444; font-weight: bold; background-color: #fff0f0; padding: 2px 4px; border-radius: 4px;' : ''
                    
                    const html = `<div style="min-width:180px;line-height:1.6; ${faultBgStyle}">
                        <div style="font-weight:600;margin-bottom:4px; ${faultStyle}">${device.name}</div>
                        <div style="${faultStyle}">${device.location}</div>
                        <div style="${faultStyle}">状态：${getStatusText(device.status)}</div>
                        <div style="${faultStyle}">pH：<span style="${phStyle}">${device.ph}</span>，温度：<span style="${tempStyle}">${device.temp}°C</span></div>
                        <div style="${faultStyle}">浊度：<span style="${ntuStyle}">${device.ntu} NTU</span></div>
                        <div style="font-size:12px;color:#666;margin-top:4px;">监测范围：2公里</div>
                    </div>`
                    window.h5InfoWindow.setContent(html)
                    window.h5InfoWindow.setPosition(position)
                    window.h5InfoWindow.open()
                })

                window.h5MarkersById[device.id] = marker
                window.h5CirclesById[device.id] = circle
            })

            // 初始化后为每个设备做逆地理命名
            try {
                deviceList.value.forEach(d => reverseNameForDeviceH5(d))
            } catch (e) {
                console.warn('H5 - 批量逆地理命名失败:', e)
            }

            // 初始化污染区域数组
            if (!window.h5PollutionAreas) {
                window.h5PollutionAreas = []
            }
		} catch (error) {
			console.error('H5 - 地图初始化失败:', error)
			mapContainer.innerHTML = `
				<div style="width:100%;height:100%;background:#f5f5f5;display:flex;align-items:center;justify-content:center;color:#f44336;">
					地图加载失败，请检查网络
				</div>
			`
		}
	}

	// 启动容器获取逻辑
	getMapContainer()
}

// 修改原 initMap 方法，适配小程序地图初始化
const initMap = () => {
	console.log('小程序 - 初始化地图组件')
	// 仅保留地图初始化日志，不修改 computed 属性
}

// 完善 getMarkerIcon 方法（确保图标路径正确，避免 404）
const getMarkerIcon = (deviceId) => {
	// 1. 优先使用项目内实际存在的图标（需在 static/images 下放置对应图标）
	const device = deviceList.value.find(d => d.id === deviceId)
	if (device) {
		switch(device.status) {
			case 'online':
				return '/static/images/marker-online.png' // 在线图标（绿色）
			case 'offline':
				return '/static/images/marker-offline.png' // 离线图标（灰色）
			case 'fault':
				return '/static/images/marker-fault.png' // 故障图标（红色）
		}
	}
	// 2. 兜底：使用腾讯地图默认图标（避免路径错误导致标记点丢失）
	return 'https://mapapi.qq.com/webapi/staticimage/v2?size=20x20&color=FF0000&format=png'
}

// 获取状态颜色（H5 用 SVG dataURL 渲染图标）
const getStatusColor = (status) => {
    if (status === 'online') return '#4cd964'
    if (status === 'fault') return '#dd524d'
    return '#999999'
}

// 获取圆形围栏填充颜色
const getCircleFillColor = (status) => {
    if (status === 'online') return '#2196F3'      // 蓝色
    if (status === 'fault') return '#FF5722'        // 橙红色
    return '#607D8B'                                // 蓝灰色
}

// 获取圆形围栏边框颜色
const getCircleStrokeColor = (status) => {
    if (status === 'online') return '#1976D2'      // 深蓝色
    if (status === 'fault') return '#E64A19'       // 深橙红色
    return '#455A64'                               // 深蓝灰色
}


// H5：根据坐标给监测点命名（优先 REST，失败回退 JS Geocoder）
function reverseNameForDeviceH5(device) {
    // #ifdef H5
    // 如果已经有地址了，跳过逆地理编码
    if (device.location && device.location !== '待获取地址' && !device.location.includes('待获取')) {
        return
    }
    
    // 生成缓存键
    const cacheKey = `${device.latitude},${device.longitude}`
    
    // 检查缓存
    if (reverseGeocodeCache.has(cacheKey)) {
        device.location = reverseGeocodeCache.get(cacheKey)
        return
    }
    
    // 防抖：清除之前的定时器
    if (reverseGeocodeTimers.has(device.id)) {
        clearTimeout(reverseGeocodeTimers.get(device.id))
    }
    
    // 设置新的定时器
    const timer = setTimeout(() => {
        reverseNameViaRESTH5(device)
            .then(result => {
                if (result && result.location) {
                    reverseGeocodeCache.set(cacheKey, result.location)
                }
            })
            .catch(() => {
                console.warn('REST逆地理编码失败，尝试JS Geocoder')
                return reverseNameViaJsGeocoderH5(device)
            })
            .catch(() => {
                console.warn('所有逆地理编码方法都失败了')
            })
            .finally(() => {
                reverseGeocodeTimers.delete(device.id)
            })
    }, 500) // 500ms防抖
    
    reverseGeocodeTimers.set(device.id, timer)
    // #endif
}

// H5：优先使用腾讯 WebService 逆地址解析（更稳定）
function reverseNameViaRESTH5(device) {
    // #ifdef H5
    return new Promise((resolve, reject) => {
        try {
            const lat = device.latitude
            const lng = device.longitude
            const key = mapConfig.value.key
            const url = `https://apis.map.qq.com/ws/geocoder/v1/?location=${lat},${lng}&key=${encodeURIComponent(key)}&get_poi=0&output=jsonp`
            jsonpRequest(url, 'callback', 8000)
              .then(json => {
                if (!json || json.status !== 0 || !json.result) {
                  reject(new Error('REST geocoder failed'))
                  return
                }
                const comp = json.result.address_component || {}
                const district = comp.district || comp.city || ''
                const niceName = district ? `${district}监测点` : device.name
                if (/^监测点\\d{3}$/.test(device.name)) {
                  device.name = niceName
                }
                device.location = json.result.address || device.location
                deviceList.value = deviceList.value.map(d => d.id === device.id ? { ...device } : d)
                const marker = window.h5MarkersById?.[device.id]
                if (marker) marker.setTitle(device.name)
                resolve()
              })
              .catch(err => reject(err))
        } catch (e) {
            reject(e)
        }
    })
    // #endif
}

// H5：回退 JS SDK Geocoder
function reverseNameViaJsGeocoderH5(device) {
    // #ifdef H5
    if (!window.qq?.maps) return Promise.reject(new Error('qq.maps not ready'))
    return new Promise((resolve) => {
        try {
            const geocoder = new window.qq.maps.Geocoder({
                complete: (result) => {
                    const comp = result?.detail?.addressComponents || {}
                    const district = comp.district || comp.city || ''
                    const street = comp.street || ''
                    const niceName = district ? `${district}监测点` : device.name
                    if (/^监测点\d{3}$/.test(device.name)) {
                        device.name = niceName
                    }
                    const fullAddr = result?.detail?.address || `${district}${street}` || device.location
                    device.location = fullAddr
                    deviceList.value = deviceList.value.map(d => d.id === device.id ? { ...device } : d)
                    const marker = window.h5MarkersById?.[device.id]
                    if (marker) marker.setTitle(device.name)
                    resolve()
                },
                error: () => resolve()
            })
            geocoder.getAddress(new window.qq.maps.LatLng(device.latitude, device.longitude))
        } catch (e) {
            resolve()
        }
    })
    // #endif
}

// 通用 JSONP 请求（绕过 CORS）
function jsonpRequest(url, callbackParam = 'callback', timeout = 8000) {
    return new Promise((resolve, reject) => {
        try {
            const cbName = `_jsonp_cb_${Date.now()}_${Math.floor(Math.random() * 10000)}`
            const sep = url.includes('?') ? '&' : '?'
            const finalUrl = `${url}${sep}${callbackParam}=${cbName}`
            const script = document.createElement('script')
            let timer = null
            
            // 创建全局回调函数
            window[cbName] = (data) => {
                clearTimeout(timer)
                resolve(data)
                cleanup()
            }
            
            const cleanup = () => {
                try { 
                    delete window[cbName] 
                } catch (e) { 
                    window[cbName] = undefined 
                }
                if (script.parentNode) {
                    script.parentNode.removeChild(script)
                }
            }
            
            script.src = finalUrl
            script.onerror = () => {
                clearTimeout(timer)
                cleanup()
                reject(new Error('JSONP script error'))
            }
            
            timer = setTimeout(() => {
                cleanup()
                reject(new Error('JSONP timeout'))
            }, timeout)
            
            document.head.appendChild(script)
        } catch (e) {
            reject(e)
        }
    })
}

const buildStatusSvgDataUrl = (color, status = 'online') => {
    let svg
    if (status === 'fault') {
        // 故障状态：红色带感叹号的图标
        svg = `<svg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'>
          <circle cx='12' cy='12' r='10' fill='${color}' stroke='#ff0000' stroke-width='2' />
          <circle cx='12' cy='12' r='6' fill='white' opacity='0.9' />
          <text x='12' y='16' text-anchor='middle' font-family='Arial' font-size='12' font-weight='bold' fill='#ff0000'>!</text>
        </svg>`
    } else {
        // 正常状态：普通圆形图标
        svg = `<svg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'>
          <circle cx='12' cy='12' r='10' fill='${color}' />
          <circle cx='12' cy='12' r='4' fill='white' opacity='0.2' />
        </svg>`
    }
    return 'data:image/svg+xml;utf8,' + encodeURIComponent(svg)
}

// 标记点击事件
const onMarkerTap = (e) => {
	const markerId = e.detail.markerId
	const device = deviceList.value.find(d => d.id === markerId)
	if (device) {
		selectDevice(device)
	}
}

// 地图区域变化事件
const onRegionChange = (e) => {
	console.log('地图区域变化:', e.detail)
}

// 地图更新事件（包括缩放）
const onMapUpdated = (e) => {
	console.log('地图更新:', e)
	// 更新地图配置中的缩放级别
	if (e.detail && e.detail.scale) {
		mapConfig.value.zoom = e.detail.scale
		console.log('地图缩放级别更新为:', e.detail.scale)
	}
}

// 地图点击事件
const onMapTap = (e) => {
	console.log('地图点击:', e.detail)
}

// 加载设备数据
async function loadDeviceData() {
	console.log('加载设备数据...')
	try {
		// 从后端API获取所有设备信息
		const res = await getMapDeviceList()
		if (res && res.code === 200 && res.obj) {
			const backendDevices = res.obj
			console.log('从后端获取到设备数据:', backendDevices)
			
			// 转换后端数据格式为前端格式
			const convertedDevices = backendDevices.map(device => ({
				id: device.id,
				name: device.name,
				location: device.location || '待获取地址',
				latitude: parseFloat(device.latitude) || 38.814788,
				longitude: parseFloat(device.longitude) || 115.489120,
				status: device.status || 'online',
				ph: 7.0, // 默认值，后续从水质数据API获取
				temp: 25.0,
				ntu: 1000,
				deviceCode: device.deviceCode,
				deviceType: device.deviceType,
				manufacturer: device.manufacturer
			}))
			
			// 保留监测点001，添加其他真实设备数据
			const newDeviceList = [realDeviceData.value] // 保留监测点001
			
			// 添加其他真实设备（排除监测点001，避免重复）
			convertedDevices.forEach(device => {
				if (device.id !== REAL_DEVICE_ID) {
					newDeviceList.push(device)
				}
			})
			
			// 更新设备列表
			deviceList.value = newDeviceList
			updateStats()
			
			// 为每个设备获取最新水质数据
			for (let device of deviceList.value) {
				try {
					const dataRes = await getDeviceLatestData(device.id)
					if (dataRes && dataRes.code === 200 && dataRes.obj) {
						const data = dataRes.obj
						device.ph = data.ph || device.ph
						device.temp = data.temp || device.temp
						device.ntu = data.ntu || device.ntu
						device.status = data.status || device.status
					}
				} catch (e) {
					console.warn(`获取设备${device.id}水质数据失败:`, e)
				}
			}
			
			updateStats()
		} else {
			console.warn('获取设备列表失败，使用默认数据')
		}
	} catch (e) {
		console.error('加载设备数据失败:', e)
		// 如果API调用失败，继续使用现有的数据
	}
	
	// 仍然获取监测点001的真实数据作为补充
	fetchRealDeviceLatest()
}

// 拉取监测点001的最新数据（来自 Redis）
async function fetchRealDeviceLatest() {
    try {
        const deviceId = REAL_DEVICE_ID
        const res = await getLatestRedisData(deviceId)
        if (res && res.code === 200 && res.obj) {
            const d = res.obj
            // 更新真实数据对象
            if (typeof d.ph === 'number') realDeviceData.value.ph = +d.ph
            if (typeof d.temp === 'number') realDeviceData.value.temp = +d.temp
            if (typeof d.ntu === 'number') realDeviceData.value.ntu = Math.round(d.ntu)
            if (d.status) realDeviceData.value.status = d.status
            else realDeviceData.value.status = computeStatusFromMetrics(realDeviceData.value.ph, realDeviceData.value.temp, realDeviceData.value.ntu)
            if (d.latitude && d.longitude) {
                realDeviceData.value.latitude = d.latitude
                realDeviceData.value.longitude = d.longitude
            }
            if (d.location) realDeviceData.value.location = d.location
            
            // 更新设备列表中的监测点001
            deviceList.value[0] = { ...realDeviceData.value }
            updateStats()
        }
    } catch (e) {
        console.error('获取真实数据失败:', e)
    }
}

// 定时更新真实数据
let realDataTimer = null
function startRealDataTimer() {
    if (realDataTimer) clearInterval(realDataTimer)
    // 每10秒更新一次真实数据
    realDataTimer = setInterval(() => {
        fetchRealDeviceLatest()
    }, 10000)
}

function stopRealDataTimer() {
    if (realDataTimer) {
        clearInterval(realDataTimer)
        realDataTimer = null
    }
}



// 手动请求定位
const requestLocation = () => {
	console.log('用户手动请求定位')
	uni.showLoading({ title: '正在定位...' })

	// 1. 定义加载提示关闭函数（统一管理）
	const closeLoading = () => {
		if (uni.getStorageSync('locationLoading')) { // 用缓存标记避免重复关闭
			uni.hideLoading()
			uni.removeStorageSync('locationLoading')
		}
	}
	uni.setStorageSync('locationLoading', true) // 标记加载中

	// 2. 定位超时兜底关闭（12秒上限）
	const loadingTimer = setTimeout(closeLoading, 12000)

	// 3. 执行定位（修改getUserLocation，让其定位完成后关闭提示）
	getUserLocation({
		onComplete: () => {
			clearTimeout(loadingTimer)
			closeLoading()
		}
	})
}

// 选择设备
const selectDevice = (device) => {
	console.log('选择设备:', device.name)
	
	// 将地图中心定位到该监测点
	updateMapCenter(device.longitude, device.latitude)
    // H5：点击时强制触发一次逆地理命名，确保名称/地址根据当前位置刷新
    // #ifdef H5
    reverseNameForDeviceH5(device)
    // #endif
	
	// 显示设备信息弹窗
	showDeviceModal.value = true
	// 传递设备引用，确保数据变化时弹窗能实时更新
	selectedDevice.value = device
	
	// 显示定位成功提示
	uni.showToast({
		title: `已定位到${device.name}`,
		icon: 'success',
		duration: 2000
	})
}

// 获取状态文本
const getStatusText = (status) => {
	const statusMap = {
		online: '在线',
		offline: '离线',
		fault: '故障'
	}
	return statusMap[status] || '未知'
}

// 关闭设备信息弹窗
const closeDeviceModal = () => {
	showDeviceModal.value = false
	selectedDevice.value = null
}

// 开始污染预测
const startPollutionPrediction = async (device) => {
	if (isPredicting.value) return

	try {
		isPredicting.value = true
		selectedDevice.value = device

		uni.showLoading({ title: 'AI污染预测中...' })

		// 构建请求数据
		const requestData = {
			latitude: device.latitude,
			longitude: device.longitude,
			deviceId: device.id,
			deviceName: device.name,
			currentData: {
				ph: device.ph,
				temp: device.temp,
				ntu: device.ntu,
				status: device.status
			},
			timestamp: new Date().toISOString()
		}

		console.log('开始污染预测:', requestData)

		// 调用后端API
		console.log('调用污染预测API...')
		console.log('pollutionApi对象:', typeof pollutionApi)
		console.log('pollutionApi内容:', Object.keys(pollutionApi || {}))
		const res = await pollutionApi.analyzeByLocation(requestData)
		console.log('API响应:', res)

		if (res.code === 200) {
			// 处理分析结果
			predictionResult.value = {
				nearbyFactories: res.obj?.nearbyFactories || [],
				isPolluted: res.obj?.isPolluted || false,
				pollutionSourceAnalysis: res.obj?.pollutionSourceAnalysis || {},
				prediction: res.obj?.prediction || '分析完成',
				recommendations: res.obj?.recommendations || []
			}

			// 生成三天预测数据
			threeDayPrediction.value = generateThreeDayPrediction(res.obj)
			selectedDateIndex.value = 0 // 默认选择第一天

			// 根据第一天的情况显示污染区域
			const firstDay = threeDayPrediction.value[0]
			if (firstDay.isPolluted) {
				console.log('第一天检测到污染，显示污染区域')
				showPollutionArea(device.latitude, device.longitude, 2000)
			} else {
				console.log('第一天未检测到污染，不显示污染区域')
				clearPollutionAreas()
			}

			showPredictionModal.value = true

			uni.showToast({
				title: '污染预测完成',
				icon: 'success'
			})
		} else {
			console.error('API响应失败:', res)
			uni.showToast({
				title: res.msg || '预测失败',
				icon: 'error'
			})
		}
		} catch (error) {
		console.error('污染预测失败:', error)
		uni.showToast({
			title: '网络错误',
			icon: 'error'
		})
	} finally {
		isPredicting.value = false
		uni.hideLoading()
	}
}

// 生成三天预测数据
const generateThreeDayPrediction = (apiResult) => {
  const today = new Date()
  const predictionData = []
  
  for (let i = 0; i < 3; i++) {
    const date = new Date(today)
    date.setDate(today.getDate() + i)
    
    const dayStr = i === 0 ? '今天' : i === 1 ? '明天' : '后天'
    const dateStr = `${date.getMonth() + 1}.${date.getDate()}`
    
    let status, statusText, concentration, description, isPolluted, pollutionReason
    
    if (apiResult?.isPolluted) {
      if (i === 0) {
        // 今天有污染
        status = 'polluted'
        statusText = '有污染'
        concentration = '150-200 μg/m³'
        description = '检测到轻度污染，建议减少户外活动'
        isPolluted = true
        pollutionReason = apiResult.pollutionSourceAnalysis?.primarySuspect?.name || '附近化工厂'
      } else if (i === 1) {
        // 明天污染减轻
        status = 'warning'
        statusText = '轻度污染'
        concentration = '80-120 μg/m³'
        description = '污染浓度下降，但仍需注意防护'
        isPolluted = true
        pollutionReason = '污染源持续影响'
      } else {
        // 后天恢复正常
        status = 'normal'
        statusText = '正常'
        concentration = '30-50 μg/m³'
        description = '污染已消散，空气质量良好'
        isPolluted = false
        pollutionReason = ''
      }
    } else {
      // 没有污染的情况 - 模拟不同的污染情况
      if (i === 0) {
        // 今天正常
        status = 'normal'
        statusText = '正常'
        concentration = '20-40 μg/m³'
        description = '空气质量良好，适合户外活动'
        isPolluted = false
        pollutionReason = ''
      } else if (i === 1) {
        // 明天可能有轻微污染
        status = 'warning'
        statusText = '轻度污染'
        concentration = '60-80 μg/m³'
        description = '预计有轻微污染，注意防护'
        isPolluted = true
        pollutionReason = '气象条件变化'
      } else {
        // 后天恢复正常
        status = 'normal'
        statusText = '正常'
        concentration = '25-35 μg/m³'
        description = '空气质量恢复正常'
        isPolluted = false
        pollutionReason = ''
      }
    }
    
    predictionData.push({
      date: `${dateStr} (${dayStr})`,
      status,
      statusText,
      concentration,
      description,
      isPolluted,
      pollutionReason
    })
  }
  
  return predictionData
}

// 显示污染区域
const showPollutionArea = (latitude, longitude, radius = 2000) => {
	console.log('显示污染区域:', { latitude, longitude, radius })

	// 创建污染区域数据（默认2公里半径，可自定义）
	const pollutionArea = {
		id: 'pollution_area_' + Date.now(),
		latitude: latitude,
		longitude: longitude,
		radius: radius, // 可自定义半径
		type: 'pollution',
		strokeColor: '#ff4444',
		fillColor: '#ff4444',
		strokeWidth: 3,
		opacity: 0.3
	}

	pollutionAreas.value.push(pollutionArea)
	showPollutionAreas.value = true

	// 在H5地图上添加污染区域覆盖物
	// #ifdef H5
	if (window.h5MapInstance && window.qq?.maps) {
		const center = new window.qq.maps.LatLng(latitude, longitude)

		// 创建圆形覆盖物
		const circle = new window.qq.maps.Circle({
			center: center,
			radius: radius, // 使用传入的半径
			map: window.h5MapInstance,
			strokeColor: new window.qq.maps.Color(255, 68, 68, 0.8),
			fillColor: new window.qq.maps.Color(255, 68, 68, 0.3),
			strokeWeight: 3
		})

		// 保存圆形对象以便后续清除
		if (!window.h5PollutionAreas) {
			window.h5PollutionAreas = []
		}
		window.h5PollutionAreas.push(circle)

		console.log('H5地图污染区域显示完成')
	}
	// #endif

	// 在小程序地图上添加污染区域
	// #ifdef MP-WEIXIN
	// 小程序原生map组件暂不支持圆形覆盖物，这里只更新状态
	console.log('小程序地图污染区域状态已更新')
	// #endif
}

// 清除污染区域
const clearPollutionAreas = () => {
	console.log('清除污染区域')

	// 清除H5地图上的污染区域
	// #ifdef H5
	if (window.h5PollutionAreas) {
		window.h5PollutionAreas.forEach(circle => {
			circle.setMap(null)
		})
		window.h5PollutionAreas = []
	}
	// #endif

	pollutionAreas.value = []
	showPollutionAreas.value = false

	uni.showToast({
		title: '污染区域已清除',
		icon: 'success'
	})
}

// 显示污染区域信息
const showPollutionAreaInfo = () => {
	if (pollutionAreas.value.length === 0) {
		uni.showToast({
			title: '暂无污染区域',
			icon: 'none'
		})
		return
	}

	const areaInfo = pollutionAreas.value.map(area => 
		`半径: ${area.radius / 1000}km\n坐标: ${area.latitude}, ${area.longitude}`
	).join('\n\n')

	uni.showModal({
		title: '污染区域信息',
		content: `共 ${pollutionAreas.value.length} 个污染区域:\n\n${areaInfo}`,
		showCancel: false,
		confirmText: '确定'
	})
}

// 模拟轻度污染
const simulateLightPollution = async () => {
	if (isSimulating.value || !selectedDevice.value) return

	try {
		isSimulating.value = true

		uni.showLoading({ title: '模拟轻度污染中...' })

		// 清除现有污染区域
		clearPollutionAreas()

		// 模拟轻度污染数据
		const simulatedData = {
			isPolluted: true,
			pollutionSourceAnalysis: {
				isPolluted: true,
				primarySuspect: {
					id: 'simulated_factory_light_001',
					name: '模拟轻工业厂',
					distance: 2.5,
					riskLevel: 'low',
					industry: '轻工业',
					mainPollutants: '轻微有机物',
					latitude: selectedDevice.value.latitude + 0.008,
					longitude: selectedDevice.value.longitude + 0.008
				},
				suspectedFactories: [
					{
						id: 'simulated_factory_light_001',
						name: '模拟轻工业厂',
						distance: 2.5,
						riskLevel: 'low',
						industry: '轻工业',
						mainPollutants: '轻微有机物'
					}
				],
				message: '检测到轻度污染，疑似来源于附近轻工业厂'
			},
			prediction: `⚠️ **轻度污染检测报告** ⚠️

**检测时间**: ${new Date().toLocaleString()}
**污染等级**: 轻度污染
**主要污染物**: 轻微有机物
**污染源**: 模拟轻工业厂 (距离2.5km)

**污染影响范围**: 半径1公里
**预计影响人群**: 约500人
**环境风险**: 低风险

**时间预测**:
- 第1天 (今天): 污染浓度维持当前水平
- 第2天 (明天): 预计浓度下降20-30%
- 第3天 (后天): 预计恢复正常水平

**建议措施**:
1. 加强水质监测频率
2. 通知相关企业进行自查
3. 持续观察污染指标变化
4. 准备应急处理预案

**注意**: 此为模拟数据，仅用于演示系统功能`,
			recommendations: [
				'加强水质监测频率至每30分钟一次',
				'通知相关企业进行环保自查',
				'持续观察污染指标变化趋势',
				'准备轻度污染应急处理预案',
				'定期发布水质监测报告'
			],
			nearbyFactories: [
				{
					id: 'simulated_factory_light_001',
					name: '模拟轻工业厂',
					distance: 2.5,
					riskLevel: 'low',
					industry: '轻工业',
					mainPollutants: '轻微有机物'
				}
			]
		}

		// 更新预测结果
		predictionResult.value = simulatedData
		simulatedPollutionData.value = simulatedData
		isSimulatedPollution.value = true

		// 显示污染区域（1公里半径）
		showPollutionArea(selectedDevice.value.latitude, selectedDevice.value.longitude, 1000)

		uni.hideLoading()
		uni.showToast({
			title: '轻度污染模拟完成',
			icon: 'success'
		})

		console.log('轻度污染模拟完成，污染区域已显示')

	} catch (error) {
		console.error('轻度污染模拟失败:', error)
		uni.hideLoading()
		uni.showToast({
			title: '模拟失败',
			icon: 'error'
		})
	} finally {
		isSimulating.value = false
	}
}

// 模拟严重污染
const simulatePollution = async () => {
	if (isSimulating.value || !selectedDevice.value) return

	try {
		isSimulating.value = true

		uni.showLoading({ title: '模拟严重污染中...' })

		// 清除现有污染区域
		clearPollutionAreas()

		// 模拟严重污染数据
		const simulatedData = {
			isPolluted: true,
			pollutionSourceAnalysis: {
				isPolluted: true,
				primarySuspect: {
					id: 'simulated_factory_001',
					name: '模拟化工厂A',
					distance: 1.2,
					riskLevel: 'high',
					industry: '化工制造',
					mainPollutants: '重金属、有机污染物',
					latitude: selectedDevice.value.latitude + 0.01,
					longitude: selectedDevice.value.longitude + 0.01
				},
				suspectedFactories: [
					{
						id: 'simulated_factory_001',
						name: '模拟化工厂A',
						distance: 1.2,
						riskLevel: 'high',
						industry: '化工制造',
						mainPollutants: '重金属、有机污染物'
					},
					{
						id: 'simulated_factory_002',
						name: '模拟化工厂B',
						distance: 2.8,
						riskLevel: 'medium',
						industry: '石油化工',
						mainPollutants: '挥发性有机物'
					}
				],
				message: '检测到严重污染，疑似来源于附近化工厂'
			},
			prediction: `🚨 **严重污染预警报告** 🚨

**检测时间**: ${new Date().toLocaleString()}
**污染等级**: 严重污染
**主要污染物**: 重金属、有机污染物
**污染源**: 模拟化工厂A (距离1.2km)

**污染影响范围**: 半径2公里
**预计影响人群**: 约5000人
**环境风险**: 高风险

**时间预测**:
- 第1天 (今天): 污染浓度达到峰值，需要立即处理
- 第2天 (明天): 应急处理后浓度下降50-60%
- 第3天 (后天): 持续处理后浓度下降80-90%

**紧急建议**:
1. 立即启动应急预案
2. 疏散影响区域内人员
3. 通知环保部门进行现场调查
4. 加强水质监测频率
5. 准备应急处理设备

**注意**: 此为模拟数据，仅用于演示系统功能`,
			recommendations: [
				'立即启动环境污染应急预案',
				'疏散污染影响区域内的人员',
				'通知环保部门进行现场调查',
				'加强水质监测频率至每5分钟一次',
				'准备应急处理设备和物资',
				'发布污染预警信息给周边居民'
			],
			nearbyFactories: [
				{
					id: 'simulated_factory_001',
					name: '模拟化工厂A',
					distance: 1.2,
					riskLevel: 'high',
					industry: '化工制造',
					mainPollutants: '重金属、有机污染物'
				},
				{
					id: 'simulated_factory_002',
					name: '模拟化工厂B',
					distance: 2.8,
					riskLevel: 'medium',
					industry: '石油化工',
					mainPollutants: '挥发性有机物'
				}
			]
		}

		// 更新预测结果
		predictionResult.value = simulatedData
		simulatedPollutionData.value = simulatedData
		isSimulatedPollution.value = true

		// 显示污染区域（2公里半径）
		showPollutionArea(selectedDevice.value.latitude, selectedDevice.value.longitude, 2000)

		uni.hideLoading()
		uni.showToast({
			title: '严重污染模拟完成',
			icon: 'success'
		})

		console.log('严重污染模拟完成，污染区域已显示')

	} catch (error) {
		console.error('严重污染模拟失败:', error)
		uni.hideLoading()
		uni.showToast({
			title: '模拟失败',
			icon: 'error'
		})
	} finally {
		isSimulating.value = false
	}
}

// 重置污染模拟状态
const resetPollutionSimulation = () => {
	isSimulatedPollution.value = false
	simulatedPollutionData.value = null
	clearPollutionAreas()
	
	// 重新获取真实数据
	if (selectedDevice.value) {
		startPollutionPrediction(selectedDevice.value)
	}

	uni.showToast({
		title: '已重置为真实数据',
		icon: 'success'
	})
}

// 选择日期标签
const selectDate = (index) => {
  if (!selectedDevice.value || !threeDayPrediction.value[index]) return
  
  selectedDateIndex.value = index
  const selectedDay = threeDayPrediction.value[index]
  
  console.log(`选择日期: ${selectedDay.date}, 污染状态: ${selectedDay.isPolluted}`)
  
  // 根据选择的日期更新地图污染区域
  if (selectedDay.isPolluted) {
    console.log(`${selectedDay.date} 有污染，显示污染区域`)
    showPollutionArea(selectedDevice.value.latitude, selectedDevice.value.longitude, 2000)
    
    // 显示污染原因
    if (selectedDay.pollutionReason) {
      uni.showToast({
        title: `污染原因: ${selectedDay.pollutionReason}`,
        icon: 'none',
        duration: 3000
      })
    }
  } else {
    console.log(`${selectedDay.date} 无污染，清除污染区域`)
    clearPollutionAreas()
    
    uni.showToast({
      title: `${selectedDay.date} 空气质量良好`,
      icon: 'success',
      duration: 2000
    })
  }
}

// 清除所有预测数据
const clearAllPredictionData = () => {
  showPredictionModal.value = false
  selectedDevice.value = null
  predictionResult.value = null
  threeDayPrediction.value = []
  selectedDateIndex.value = 0
  clearPollutionAreas()
  console.log('清除所有预测数据')
}

// 关闭污染预测弹窗
const closePredictionModal = () => {
	showPredictionModal.value = false
	// 保留污染区域和预测数据，只关闭弹窗
	console.log('关闭预测弹窗，保留污染区域和预测数据')
}

// 监听设备数据变化，实时更新 H5 标记图标与位置
watch(deviceList, (newList) => {
	// 如果弹窗正在显示某个设备，更新弹窗数据
	if (showDeviceModal.value && selectedDevice.value) {
		const updatedDevice = newList.find(d => d.id === selectedDevice.value.id)
		if (updatedDevice) {
			selectedDevice.value = updatedDevice
		}
	}
    // #ifdef H5
    if (!window.h5MarkersById || !window.qq?.maps) return
    newList.forEach(device => {
        let marker = window.h5MarkersById[device.id]
        let circle = window.h5CirclesById[device.id]
        
        // 新增设备时创建 Marker 和 Circle
        if (!marker) {
            const pos = new window.qq.maps.LatLng(device.latitude, device.longitude)
            marker = new window.qq.maps.Marker({ position: pos, map: window.h5MapInstance, title: device.name })
            window.h5MarkersById[device.id] = marker
            
            // 创建圆形围栏
            const fillColor = new window.qq.maps.Color(33, 150, 243, 0.3) // 蓝色，30%透明度
            const strokeColor = new window.qq.maps.Color(33, 150, 243, 0.8) // 蓝色边框，80%透明度
            
            circle = new window.qq.maps.Circle({
                center: pos,
                radius: 2000, // 2公里半径，单位：米
                map: window.h5MapInstance,
                fillColor: fillColor,
                strokeColor: strokeColor,
                strokeWeight: 3
            })
            window.h5CirclesById[device.id] = circle
            
            // 绑定点击信息窗
            window.qq.maps.event.addListener(marker, 'click', () => {
                // 使用监测点分布列表中的设备数据
                const currentDevice = deviceList.value.find(d => d.id === device.id)
                if (currentDevice) {
                    const pos = new window.qq.maps.LatLng(currentDevice.latitude, currentDevice.longitude)
                    const isFault = currentDevice.status === 'fault'
                    const faultStyle = isFault ? 'color: #ff4444; font-weight: bold;' : ''
                    const faultBgStyle = isFault ? 'background-color: #fff5f5; border: 2px solid #ff4444; border-radius: 8px; padding: 8px;' : ''
                    
                    // 判断每个数据项是否异常
                    const phFault = isPhFault(currentDevice.ph)
                    const tempFault = isTempFault(currentDevice.temp)
                    const ntuFault = isNtuFault(currentDevice.ntu)
                    
                    const phStyle = phFault ? 'color: #ff4444; font-weight: bold; background-color: #fff0f0; padding: 2px 4px; border-radius: 4px;' : ''
                    const tempStyle = tempFault ? 'color: #ff4444; font-weight: bold; background-color: #fff0f0; padding: 2px 4px; border-radius: 4px;' : ''
                    const ntuStyle = ntuFault ? 'color: #ff4444; font-weight: bold; background-color: #fff0f0; padding: 2px 4px; border-radius: 4px;' : ''
                    
                    const html = `<div style="min-width:180px;line-height:1.6; ${faultBgStyle}">
                        <div style="font-weight:600;margin-bottom:4px; ${faultStyle}">${currentDevice.name}</div>
                        <div style="${faultStyle}">${currentDevice.location}</div>
                        <div style="${faultStyle}">状态：${getStatusText(currentDevice.status)}</div>
                        <div style="${faultStyle}">pH：<span style="${phStyle}">${currentDevice.ph}</span>，温度：<span style="${tempStyle}">${currentDevice.temp}°C</span></div>
                        <div style="${faultStyle}">浊度：<span style="${ntuStyle}">${currentDevice.ntu} NTU</span></div>
                        <div style="font-size:12px;color:#666;margin-top:4px;">监测范围：2公里</div>
                    </div>`
                    window.h5InfoWindow?.setContent(html)
                    window.h5InfoWindow?.setPosition(pos)
                    window.h5InfoWindow?.open()
                }
            })
            // 新增即触发逆地理命名
            reverseNameForDeviceH5(device)
        } else {
            // 更新现有标记的位置和图标
            const pos = new window.qq.maps.LatLng(device.latitude, device.longitude)
            marker.setPosition(pos)
            
            // 更新圆形围栏位置和样式
            if (circle) {
                const fillColor = new window.qq.maps.Color(33, 150, 243, 0.3) // 蓝色，30%透明度
                const strokeColor = new window.qq.maps.Color(33, 150, 243, 0.8) // 蓝色边框，80%透明度
                circle.setCenter(pos)
                circle.setOptions({
                    fillColor: fillColor,
                    strokeColor: strokeColor,
                    strokeWeight: 3
                })
            }
            
            // 更新标记图标
            const color = getStatusColor(device.status)
            const iconUrl = buildStatusSvgDataUrl(color, device.status)
            const size = new window.qq.maps.Size(24, 24)
            const markerImage = new window.qq.maps.MarkerImage(iconUrl, null, null, null, size)
            marker.setIcon(markerImage)
            
            // 如果信息窗口当前打开的是这个设备，更新其内容
            if (window.h5InfoWindow && window.h5InfoWindow.getMap()) {
                const currentDevice = deviceList.value.find(d => d.id === device.id)
                if (currentDevice) {
                    const isFault = currentDevice.status === 'fault'
                    const faultStyle = isFault ? 'color: #ff4444; font-weight: bold;' : ''
                    const faultBgStyle = isFault ? 'background-color: #fff5f5; border: 2px solid #ff4444; border-radius: 8px; padding: 8px;' : ''
                    
                    // 判断每个数据项是否异常
                    const phFault = isPhFault(currentDevice.ph)
                    const tempFault = isTempFault(currentDevice.temp)
                    const ntuFault = isNtuFault(currentDevice.ntu)
                    
                    const phStyle = phFault ? 'color: #ff4444; font-weight: bold; background-color: #fff0f0; padding: 2px 4px; border-radius: 4px;' : ''
                    const tempStyle = tempFault ? 'color: #ff4444; font-weight: bold; background-color: #fff0f0; padding: 2px 4px; border-radius: 4px;' : ''
                    const ntuStyle = ntuFault ? 'color: #ff4444; font-weight: bold; background-color: #fff0f0; padding: 2px 4px; border-radius: 4px;' : ''
                    
                    const html = `<div style="min-width:180px;line-height:1.6; ${faultBgStyle}">
                        <div style="font-weight:600;margin-bottom:4px; ${faultStyle}">${currentDevice.name}</div>
                        <div style="${faultStyle}">${currentDevice.location}</div>
                        <div style="${faultStyle}">状态：${getStatusText(currentDevice.status)}</div>
                        <div style="${faultStyle}">pH：<span style="${phStyle}">${currentDevice.ph}</span>，温度：<span style="${tempStyle}">${currentDevice.temp}°C</span></div>
                        <div style="${faultStyle}">浊度：<span style="${ntuStyle}">${currentDevice.ntu} NTU</span></div>
                        <div style="font-size:12px;color:#666;margin-top:4px;">监测范围：2公里</div>
                    </div>`
                    window.h5InfoWindow.setContent(html)
                    window.h5InfoWindow.setPosition(pos)
                }
            }
        }
    })
    // #endif
}, { deep: true })
</script>

<style lang="scss" scoped>
.container {
    min-height: 0; /* 允许子元素控制高度 */
    height: 100vh; /* 占满视口高度，交由子元素自适应 */
	display: flex;
	flex-direction: column;
	background-color: #f5f5f5;
}


/* 同时检查父容器 .map-container 是否有高度限制，确保子元素能撑开 */
.map-container {
	background-color: #ffffff;
	border-radius: 10rpx;
	padding: 30rpx;
	margin: 20rpx;
	box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.1);
    flex: 1 1 auto; /* 占据剩余空间，自适应父布局 */
    min-height: 0; /* 允许内部元素自适应 */
    display: flex;
    flex-direction: column;
}

/* 全屏放大状态 */
.map-container.fullscreen {
  position: fixed;
  inset: 0; /* top/right/bottom/left: 0 */
  z-index: 9999;
  margin: 0;
  padding: 10rpx; /* 保持轻微留白，可按需改为0 */
  border-radius: 0;
}

.map-header {
	display: flex;
	justify-content: space-between;
	align-items: center;
	margin-bottom: 20rpx;
}

.header-right {
	display: flex;
	align-items: center;
	gap: 20rpx;
}

.location-btn {
	display: flex;
	align-items: center;
	gap: 8rpx;
	padding: 12rpx 20rpx;
	background-color: #4CAF50;
	color: white;
	border: none;
	border-radius: 20rpx;
	font-size: 24rpx;
	box-shadow: 0 2rpx 8rpx rgba(76, 175, 80, 0.3);
	transition: all 0.3s ease;
}

.location-btn:active {
	transform: scale(0.95);
	background-color: #45a049;
}

.location-icon {
	font-size: 28rpx;
}

.location-text {
	font-size: 24rpx;
	font-weight: 500;
}

.map-title {
	font-size: 28rpx;
	font-weight: bold;
	color: #333;
}

.device-count {
	font-size: 22rpx;
	color: #666;
}

.user-location {
	margin: 10rpx 0;
	padding: 15rpx 20rpx;
	background-color: #e8f5e8;
	border-radius: 8rpx;
	border-left: 4rpx solid #4CAF50;
}

.location-text {
	font-size: 24rpx;
	color: #2E7D32;
	font-weight: 500;
}

/* 日期选择器样式 */
.date-selector {
  margin-bottom: 20rpx;
  padding: 20rpx;
  background-color: #f8f9fa;
  border-radius: 12rpx;
  border: 2rpx solid #e9ecef;
}

.selector-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 15rpx;
}

.selector-title {
  font-size: 24rpx;
  color: #333;
  font-weight: bold;
}

.clear-all-btn {
  display: flex;
  align-items: center;
  gap: 6rpx;
  padding: 8rpx 16rpx;
  background-color: #ff4444;
  color: #fff;
  border: none;
  border-radius: 8rpx;
  font-size: 20rpx;
  transition: all 0.3s ease;
}

.clear-all-btn:active {
  background-color: #cc3333;
  transform: scale(0.95);
}

.date-tags {
  display: flex;
  gap: 15rpx;
  flex-wrap: wrap;
}

.date-tag {
  flex: 1;
  min-width: 120rpx;
  padding: 15rpx 20rpx;
  border-radius: 12rpx;
  border: 2rpx solid #e9ecef;
  background-color: #fff;
  text-align: center;
  transition: all 0.3s ease;
  cursor: pointer;
}

.date-tag.active {
  border-color: #007aff;
  background-color: #e3f2fd;
  box-shadow: 0 4rpx 12rpx rgba(0, 122, 255, 0.2);
}

.date-tag.polluted {
  border-color: #ff4444;
  background-color: #fff5f5;
}

.date-tag.polluted.active {
  border-color: #ff4444;
  background-color: #ffebee;
  box-shadow: 0 4rpx 12rpx rgba(255, 68, 68, 0.2);
}

.date-text {
  font-size: 22rpx;
  font-weight: bold;
  color: #333;
  display: block;
  margin-bottom: 5rpx;
}

.status-text {
  font-size: 18rpx;
  font-weight: 500;
  display: block;
}

.status-text.polluted {
  color: #d32f2f;
}

.status-text.warning {
  color: #f57c00;
}

.status-text.normal {
  color: #2e7d32;
}

/* 修改 .map-component 样式，增加 !important 确保优先级，并添加最小高度兜底 */
.map-component {
  flex: 1 1 auto; /* 跟随父容器伸缩 */
	width: 100%;
  height: 100% !important; /* 占满父容器 */
  min-height: 200px; /* 给个兜底最小高度 */
  border-radius: 15rpx;
  overflow: hidden;
  position: relative;
  z-index: 1;
}


.map-legend {
	position: absolute;
	bottom: 20rpx;
	left: 20rpx;
	background: rgba(255, 255, 255, 0.9);
	border-radius: 10rpx;
	padding: 15rpx 20rpx;
	box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.1);
	display: flex;
	gap: 20rpx;
}

.legend-item {
	display: flex;
	align-items: center;
	gap: 10rpx;
}

.legend-color {
	width: 24rpx;
	height: 24rpx;
	border-radius: 50%;
	
	&.online { background-color: #4CAF50; }
	&.offline { background-color: #9E9E9E; }
	&.fault { background-color: #F44336; }
}

.legend-text {
	font-size: 24rpx;
	color: #333;
}

.control-panel {
	height: 400rpx;
	background-color: #ffffff;
	border-top-left-radius: 20rpx;
	border-top-right-radius: 20rpx;
	padding: 30rpx;
	box-shadow: 0 -2rpx 10rpx rgba(0, 0, 0, 0.1);
}

.panel-header {
	display: flex;
	justify-content: space-between;
	align-items: center;
	margin-bottom: 20rpx;
}

.update-hint {
    margin-top: 10rpx;
    font-size: 20rpx;
    color: #999;
}

.panel-title {
	font-size: 28rpx;
	font-weight: bold;
	color: #333;
}

.legend {
	display: flex;
	gap: 20rpx;
}

.legend-item {
	display: flex;
	align-items: center;
	gap: 8rpx;
}

.legend-dot {
	width: 12rpx;
	height: 12rpx;
	border-radius: 50%;
	
	&.online {
		background-color: #4cd964;
	}
	
	&.offline {
		background-color: #999999;
	}
	
	&.fault {
		background-color: #dd524d;
	}
}

.legend-text {
	font-size: 20rpx;
	color: #666;
}

.device-list {
	height: 300rpx;
}

.device-item {
	display: flex;
	justify-content: space-between;
	align-items: center;
	padding: 20rpx 0;
	border-bottom: 1rpx solid #f0f0f0;
	
	&:last-child {
		border-bottom: none;
	}
}

.device-info {
	flex: 1;
}

.device-header {
	display: flex;
	justify-content: space-between;
	align-items: center;
	margin-bottom: 10rpx;
}

.status-text {
    font-size: 22rpx;
    color: #666;
}

.device-name {
	font-size: 26rpx;
	font-weight: bold;
	color: #333;
}

.device-status {
	width: 12rpx;
	height: 12rpx;
	border-radius: 50%;
	
	&.online {
		background-color: #4cd964;
	}
	
	&.offline {
		background-color: #999999;
	}
	
	&.fault {
		background-color: #dd524d;
		animation: fault-blink 1.5s infinite;
	}
}

// 异常数据特殊样式
.fault-device {
	background-color: #fff5f5;
	border-left: 4rpx solid #ff4444;
	box-shadow: 0 2rpx 8rpx rgba(255, 68, 68, 0.1);
}

.fault-name {
	color: #ff4444 !important;
	font-weight: bold;
}

.fault-status {
	color: #ff4444 !important;
	font-weight: bold;
}

.fault-location {
	color: #ff6666 !important;
}

.fault-data {
	background-color: #fff0f0;
	border-radius: 8rpx;
	padding: 8rpx;
}

.fault-data-item {
	color: #ff4444 !important;
	font-weight: bold;
}

.fault-arrow {
	animation: fault-pulse 2s infinite;
}

// 故障状态闪烁动画
@keyframes fault-blink {
	0%, 50% { opacity: 1; }
	51%, 100% { opacity: 0.3; }
}

// 故障箭头脉冲动画
@keyframes fault-pulse {
	0%, 100% { transform: scale(1); }
	50% { transform: scale(1.2); }
}

.device-location {
	font-size: 22rpx;
	color: #666;
	margin-bottom: 10rpx;
	display: block;
}

.device-data {
	display: flex;
	gap: 20rpx;
}

.data-item {
	font-size: 20rpx;
	color: #999;
}

.bottom-stats {
	display: flex;
	background-color: #ffffff;
	padding: 20rpx 0;
	border-top: 1rpx solid #f0f0f0;
}

.stat-item {
	flex: 1;
	display: flex;
	flex-direction: column;
	align-items: center;
}

.stat-number {
	font-size: 32rpx;
	font-weight: bold;
	color: #333;
	margin-bottom: 5rpx;
	
	&.online {
		color: #4cd964;
	}
	
	&.offline {
		color: #999999;
	}
	
	&.fault {
		color: #dd524d;
	}
}

.stat-label {
	font-size: 20rpx;
	color: #666;
}

/* 污染预测按钮样式 */
.device-actions {
	margin-top: 8rpx;
}

.predict-btn {
	padding: 8rpx 16rpx;
	background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
	color: #fff;
	border: none;
	border-radius: 8rpx;
	font-size: 18rpx;
	font-weight: bold;
	transition: all 0.3s ease;
}

.predict-btn:active {
	transform: scale(0.95);
	background: linear-gradient(135deg, #5a6fd8 0%, #6a4190 100%);
}

.predict-btn:disabled {
	background: #ccc;
	color: #999;
	transform: none;
}

/* 污染预测结果弹窗样式 */
.prediction-modal {
	position: fixed;
	top: 0;
	left: 0;
	right: 0;
	bottom: 0;
	background-color: rgba(0, 0, 0, 0.5);
	z-index: 10000;
	display: flex;
	align-items: center;
	justify-content: center;
	padding: 40rpx;
}

/* 污染区域控制样式 */
.pollution-area-control-section {
	margin-top: 30rpx;
	padding: 20rpx;
	background-color: #f8f9fa;
	border-radius: 12rpx;
}

.control-buttons {
	display: flex;
	gap: 20rpx;
	margin-top: 20rpx;
}

.control-btn {
	flex: 1;
	display: flex;
	align-items: center;
	justify-content: center;
	gap: 10rpx;
	padding: 20rpx;
	border-radius: 12rpx;
	border: none;
	font-size: 28rpx;
	color: #fff;
}

.clear-btn {
	background-color: #ff4444;
}

.clear-btn:active {
	background-color: #cc3333;
}

.info-btn {
	background-color: #007aff;
}

.info-btn:active {
	background-color: #0056b3;
}

/* 模拟污染控制样式 */
.simulate-pollution-section {
	margin-top: 30rpx;
	padding: 20rpx;
	background-color: #fff3cd;
	border-radius: 12rpx;
	border: 2rpx solid #ffc107;
}

.simulate-buttons {
	display: flex;
	gap: 20rpx;
	margin-top: 20rpx;
}

.simulate-btn {
	flex: 1;
	display: flex;
	align-items: center;
	justify-content: center;
	gap: 10rpx;
	padding: 20rpx;
	border-radius: 12rpx;
	border: none;
	font-size: 28rpx;
	color: #fff;
}

.light-pollution-btn {
	background-color: #ffc107;
}

.light-pollution-btn:active {
	background-color: #e0a800;
}

.light-pollution-btn:disabled {
	background-color: #6c757d;
	opacity: 0.6;
}

.simulate-pollution-btn {
	background-color: #dc3545;
}

.simulate-pollution-btn:active {
	background-color: #c82333;
}

.simulate-pollution-btn:disabled {
	background-color: #6c757d;
	opacity: 0.6;
}

.reset-btn {
	background-color: #28a745;
}

.reset-btn:active {
	background-color: #218838;
}

.modal-content {
	background-color: #fff;
	border-radius: 20rpx;
	width: 100%;
	max-width: 600rpx;
	max-height: 80vh;
	overflow: hidden;
	box-shadow: 0 10rpx 40rpx rgba(0, 0, 0, 0.3);
}

.modal-header {
	display: flex;
	justify-content: space-between;
	align-items: center;
	padding: 30rpx;
	border-bottom: 1rpx solid #f0f0f0;
	background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
}

.modal-title {
	font-size: 32rpx;
	font-weight: bold;
	color: #fff;
}

.close-btn {
	font-size: 40rpx;
	color: rgba(255, 255, 255, 0.8);
	cursor: pointer;
}

.modal-body {
	padding: 30rpx;
	max-height: 60vh;
	overflow-y: auto;
}

.device-info-section,
.pollution-status-section,
.factory-analysis-section,
.prediction-result-section,
.recommendations-section {
	margin-bottom: 30rpx;

	&:last-child {
		margin-bottom: 0;
	}
}

.section-title {
	font-size: 28rpx;
	font-weight: bold;
	color: #333;
	margin-bottom: 20rpx;
	padding-bottom: 10rpx;
	border-bottom: 2rpx solid #f0f0f0;
}

.info-item {
	display: flex;
	margin-bottom: 15rpx;

	&:last-child {
		margin-bottom: 0;
	}
}

.info-label {
	font-size: 24rpx;
	color: #666;
	width: 120rpx;
	flex-shrink: 0;
}

.info-value {
	font-size: 24rpx;
	color: #333;
	flex: 1;
}

.pollution-status {
	display: flex;
	align-items: center;
	gap: 12rpx;
	padding: 16rpx;
	border-radius: 12rpx;
	font-weight: 600;
	font-size: 28rpx;
}

.pollution-status.polluted {
	background: #ffe6e6;
	color: #d32f2f;
	border: 2rpx solid #ffcdd2;
}

.pollution-status.normal {
	background: #e8f5e8;
	color: #2e7d32;
	border: 2rpx solid #c8e6c9;
}

.factory-list {
	display: flex;
	flex-direction: column;
	gap: 15rpx;
}

.factory-item {
	background-color: #f8f9fa;
	border-radius: 12rpx;
	padding: 20rpx;
	border-left: 4rpx solid #4CAF50;
}

.factory-header {
	display: flex;
	justify-content: space-between;
	align-items: center;
	margin-bottom: 10rpx;
}

.factory-name {
	font-size: 24rpx;
	font-weight: bold;
	color: #333;
}

.factory-distance {
	font-size: 20rpx;
	color: #666;
	background-color: #e9ecef;
	padding: 4rpx 8rpx;
	border-radius: 8rpx;
}

.factory-details {
	display: flex;
	flex-direction: column;
	gap: 8rpx;
}

.factory-industry,
.factory-pollutants {
	font-size: 20rpx;
	color: #666;
}

.factory-risk {
	font-size: 20rpx;
	font-weight: bold;

	&.high { color: #ff4444; }
	&.medium { color: #ffa500; }
	&.low { color: #4cd964; }
}

.prediction-content {
	background-color: #f8f9fa;
	padding: 20rpx;
	border-radius: 12rpx;
	border: 1rpx solid #e9ecef;
}

.prediction-text {
	font-size: 24rpx;
	line-height: 1.6;
	color: #333;
	white-space: pre-wrap;
	word-break: break-word;
}

.recommendations-list {
	display: flex;
	flex-direction: column;
	gap: 10rpx;
}

.recommendation-item {
	font-size: 22rpx;
	line-height: 1.5;
	color: #333;
	padding: 10rpx 15rpx;
	background-color: #f8f9fa;
	border-radius: 8rpx;
	border-left: 3rpx solid #4CAF50;
}
</style>
